package com.shensi.appCollect.utils;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

@Slf4j
public class RSAUtil {

    private static final String KEY_ALGORITHM = "RSA";
    // 最大解密长度
    private static final int MAX_DECRYPT_BLOCK = 256;
    // 最大加密长度
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
     * @Title: getPublicKey
     * @Description:实例化公钥
     */
    public static PublicKey getPublicKey(String publicKey) throws Exception {
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKey.getBytes());
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(keySpec);
    }

    /**
     * @Title: getPrivateKey
     * @Description:实例化私钥
     */
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKey.getBytes());
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(keySpec);
    }

    /**
     * 使用私钥分段解密
     *
     * @param dataBytes     密文byte
     * @param privateKeyStr 密钥Str
     */
    public static String decryptByPrivateKeyPartition(byte[] dataBytes, String privateKeyStr) {

        String str = "";
        try {
            PrivateKey privateKey = getPrivateKey(privateKeyStr);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            int inputLen = dataBytes.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offset = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offset > 0) {
                if (inputLen - offset > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
                }
                out.write(cache, 0, cache.length);
                i++;
                offset = i * MAX_DECRYPT_BLOCK;
            }
            byte[] decryptedData = out.toByteArray();
            out.close();
            // 解密后的内容
            str = new String(decryptedData, StandardCharsets.UTF_8);

        } catch (Exception e) {
            log.error("===== 私钥分段解密：decryptByPrivateKeyPartition，失败异常：", e);
        }
        return str;
    }


    /**
     * 使用公钥加密
     *
     * @param dataBytes    密文byte
     * @param publicKeyStr 公钥Str
     */
    public static String encryptByPublicKeyPartition(byte[] dataBytes, String publicKeyStr) {

        // 加密
        String str = "";
        try {
            PublicKey publicKey = getPublicKey(publicKeyStr);
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            int inputLen = dataBytes.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            while (inputLen - offSet > 0) {
                //MAX_ENCRYPT_BLOCK 117
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(dataBytes, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(dataBytes, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedData = out.toByteArray();
            out.close();

            Base64.Encoder encoder = Base64.getEncoder();
            str = encoder.encodeToString(encryptedData);
        } catch (Exception e) {
            log.error("===== 加密失败 encryptByPublicKeyPartition ：", e);
        }
        return str;
    }


    public static void main(String[] args) {

        JSONObject request = new JSONObject();
        request.put("mobilePhone", "19981143091");
        request.put("openId", "olry9531MIOCkREX-csNYbmh8UXk");
        request.put("centerUserId", "");
        String content = request.toJSONString();

        String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo+XmS2Vg3M41XCc/cKk6nyUURzMeOGOxG9lhDdVkzJRi1PsntOYNG8vPqXOIb1humpGe4LlTLruGj7IcNY25UcO8ddVivfj5Ra6Fj0UPe8RMX+IYzP3dKwA9W/ck5vnXlxYbztPveNljJiPgk79ic8bER5fBlabr5rSwmWBeFJMvenYvlWe9bawl+3XmZPWGmQceb/K5C67sp0vu3aBjv03I8na3oWb71YFAyrCmlrlqj19of4/PX9H9zvl1CGtEqHHJc7xfbMDwBpAvEohcMg7ZBAuRfYVRWl7aNM5XPM3/XuO61USZMkhV571HEh8I9KYPpWGFQ/vqwJRIu6i8/wIDAQAB";
        String privateKey = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCj5eZLZWDczjVcJz9wqTqfJRRHMx44Y7Eb2WEN1WTMlGLU+ye05g0by8+pc4hvWG6akZ7guVMuu4aPshw1jblRw7x11WK9+PlFroWPRQ97xExf4hjM/d0rAD1b9yTm+deXFhvO0+942WMmI+CTv2JzxsRHl8GVpuvmtLCZYF4Uky96di+VZ71trCX7deZk9YaZBx5v8rkLruynS+7doGO/TcjydrehZvvVgUDKsKaWuWqPX2h/j89f0f3O+XUIa0SocclzvF9swPAGkC8SiFwyDtkEC5F9hVFaXto0zlc8zf9e47rVRJkySFXnvUcSHwj0pg+lYYVD++rAlEi7qLz/AgMBAAECggEAFTopYYp3ySFL9+t9Y/IHDaWXwsD0IQmIXrsAvvHsZDKzujHtKpjBCeCTvLah7QnfCVXi5egaxeqzutiunqEEZ3qaZgiFCWW9ozC/S5b+MmFyItj9rU8T3gXh7I9N0Dx7l63dXCRG17gQB1iONZSMA8KymTMmd2NvGio81SCODsvsPG+VIA11HJwIpyRJqvIwEuTluOFnAY1ob/yqKvEx+t74cm7E+f6+fJMhJeZIqdHPZmV8buKVVWUqbZWR9y3rmq/f2lzcXh5uhYvI3C+EKZHcjpgMqHIJHWRCZK1LYYxNQ2FDqWjwZsuqd2dcc+V9WbV+VraxBhGNx0ablrSswQKBgQDTV5lDazXRmDCHu8ViGAQD455xLL4kRz4oar7fZKenswI7ZJneukQHZAx7J3/xDvvB4vyCAGXj6xOzXl7+ZMNGIbzIBJFoMqMN6cG4rpxM41V79CvqMj8c90GSvGKC64Hyjjx0qCSAv0C3VYTtYHdfV8O5hzXvKBqC789wT73puwKBgQDGh9hKhFtEFKoG3ouThkCPV+IF4UV5adOhz9IAhmHI9GErEaBNqQPQoiV1gDi2+Y0f3EEJHAbOgLtmlj5Orz2/DP8ApJcZKGsx21l9Jaj5E6ts+Q3hq1gDLtXdwr7UHHdGfbJm6PH0v2S3VKNc+UHN1EsNH7Uf+oGAKPIetzBzjQKBgAUqhQKS4lPnRnhq7J5DPAXkUIEvuM4mN6zBPz0ytq5wv8M36FL7dqI/ndZ81rHLzfelVsrOu67gljCyQ9wwFl3mgTjac7t6UWYLqsKa8hMnE3XeOByXcdeBa8bsd/P/UcPeGjg3y/yhsDFLE97BlulrucsVNQpNjqhYuFdke531AoGAeW6h94JZqJzTGvyIdyXI22Sv1VTi/86hKfpJwxRvP1FrFcLkQFw+/yAOtX5GMnUVwwUfqojACRNojOkdF1fM9szmNOh3m2XDm21FoWylnCRR2IfF2+DIJrpBCjGSM39t3WoI8zVMuZ1P52sXuUik3VcayN46FWNOTqu83NjEBAkCgYA/ZzCjKMauTwgkzxoNBbsFRUyrAvYgCmG8bJ5/C0gxO44h6CBEDKFm3Tbt69x65xSuiJJjvMF92PFLgR+koBNDygb0d0DlKK4JZKp+Mtr9lyak1S2/dOIP7Q6xR7Q86dvfa1rVjJSj5JCU8Ie2J0R8Xeo+L8W3wOJ72yEYVJdkUw==";


        // 加密
        String publicMessage = encryptByPublicKeyPartition(content.getBytes(StandardCharsets.UTF_8), publicKey);
        String encode = URLEncoder.encode(publicMessage);
        log.info("密文-->【{}】", publicMessage);


        // 传输
        // 请求至公共前端页面


        // 解密
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] decode = decoder.decode(publicMessage.getBytes());
        String decryMessage = decryptByPrivateKeyPartition(decode, privateKey);
        log.info("明文-->【{}】", decryMessage);
    }
}
